package tools

import (
	"bufio"
	"errors"
	"fmt"
	"gitee.com/uni-minds/utils/media"
	"github.com/disintegration/imaging"
	ffmpeg "github.com/u2takey/ffmpeg-go"
	"image"
	"image/jpeg"
	"io"
	"os"
	"os/exec"
	"path"
	"strconv"
)

func ImageGenerateThumbnail(fpath string, im image.Image, thumbSize int) error {
	s := im.Bounds().Size()
	width, height := calcResize(s.X, s.Y, thumbSize, thumbSize)
	result := imaging.Thumbnail(im, width, height, imaging.Linear)

	if fp, err := os.OpenFile(fpath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644); err != nil {
		return err
	} else if err = jpeg.Encode(fp, result, &jpeg.Options{Quality: 90}); err != nil {
		return err
	} else {
		return fp.Close()
	}
}

func GenerateVideoFromFrames(root, instanceId, fnVideo string) error {
	kwargs1 := make(map[string]interface{})
	kwargs2 := make(map[string]interface{})

	kwargs1["f"] = "image2"
	kwargs2["b:v"] = "8000k"
	kwargs2["bufsize"] = "8000k"
	kwargs2["vcodec"] = "libtheora"
	kwargs2["r"] = "10"

	f_input := fmt.Sprintf("%s/%s_f%%d.png", root, instanceId)
	f_output := path.Join(root, fnVideo)

	return ffmpeg.Input(f_input, kwargs1).Output(f_output, kwargs2).OverWriteOutput().Run()
}

func GenerateVideoFromImage(imagePath, videoPath string) error {
	kwargs1 := make(map[string]interface{})
	kwargs2 := make(map[string]interface{})

	kwargs1["f"] = "image2"
	kwargs2["b:v"] = "8000k"
	kwargs2["bufsize"] = "8000k"
	kwargs2["vcodec"] = "libtheora"
	kwargs2["r"] = "10"

	f_input := imagePath
	f_output := videoPath

	return ffmpeg.Input(f_input, kwargs1).Output(f_output, kwargs2).OverWriteOutput().Run()
}

func MediaGetDuration(fullpath string) (d float64, err error) {
	dur, err := media.GetDuration(fullpath)
	//dur := 1*time.Second + 1910*time.Millisecond
	d = float64(dur.Milliseconds()) / 1000
	return d, err
	//targets := []string{"/usr/bin/ffprobe", "/usr/local/bin/ffprobe"}
	//var ffmpeg string
	//
	//for _, ffmpeg = range targets {
	//	if _, err := os.Stat(ffmpeg); err == nil {
	//		//ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 -i
	//		ok, output, _, _ := runCommand(ffmpeg, []string{"-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", "-i", fullpath})
	//		if !ok {
	//			return 0, errors.New("E;FFProbe failed")
	//		}
	//		output = strings.Trim(output, "\n")
	//		return strconv.ParseFloat(output, 10)
	//	}
	//}
	//return 0, errors.New("ffmpeg not found")

}

func FfProbe(input string) (data string, err error) {
	ok, data, _, ec := runCommand("ffprobe", []string{"-show_streams", input})
	if !ok {
		fmt.Println("E")
		return "", errors.New("E")
	} else if ec != 0 {
		return "", errors.New("error code:" + strconv.Itoa(ec))
	}
	return
}

func calcResize(wOri, hOri, wTarget, hTarget int) (wResize, hResize int) {
	ratio := float64(wOri) / float64(hOri)
	if wTarget == 0 {
		hResize = hTarget
		wResize = int(float64(hTarget) * ratio)
	} else if hTarget == 0 {
		wResize = wTarget
		hResize = int(float64(wTarget) / ratio)
	} else {
		ratio2 := float64(wTarget) / float64(hTarget)
		if ratio2 < ratio {
			wResize = wTarget
			hResize = int(float64(wTarget) / ratio)
		} else {
			hResize = hTarget
			wResize = int(float64(hTarget) * ratio)
		}
	}
	return wResize, hResize
}

func SaveToFile(fn string, data []byte) error {
	if fp, err := os.OpenFile(fn, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644); err != nil {
		return err
	} else if _, err = fp.Write(data); err != nil {
		fp.Close()
		return err
	} else {
		return fp.Close()
	}
}

func runCommand(commandName string, params []string) (ok bool, output string, outerr string, exitcode int) {
	cmd := exec.Command(commandName, params...)
	stderr, err := cmd.StderrPipe()
	if err != nil {
		ok = false
		return
	}

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		ok = false
		return
	}

	fmt.Println(cmd.String())

	cmd.Start()

	stderrReader := bufio.NewReader(stderr)
	stdoutReader := bufio.NewReader(stdout)

	//实时循环读取输出流中的一行内容

	go func() {
		for {
			line, err2 := stderrReader.ReadString('\n')
			if err2 != nil || io.EOF == err2 {
				break
			}
			//fmt.Printf(line)
			outerr += line
		}
	}()

	go func() {
		for {
			line, err2 := stdoutReader.ReadString('\n')
			if err2 != nil || io.EOF == err2 {
				break
			}
			//fmt.Printf(line)
			output += line
		}
	}()

	cmd.Wait()
	//fmt.Println("Run finish")
	exitcode = cmd.ProcessState.ExitCode()
	return true, output, outerr, exitcode
}
